import {
  BadRequestException,
  Body,
  Controller,
  Delete,
  forwardRef,
  Get,
  Inject,
  Post,
  Put,
  Query,
} from '@nestjs/common'
import { ApiOperation, ApiTags } from '@nestjs/swagger'

import { ApiResult } from '~/common/decorators/api-result.decorator'
import { ApiSecurityAuth } from '~/common/decorators/swagger.decorator'
import { DeleteDto } from '~/common/dto/delete.dto'
import { BusinessException } from '~/common/exceptions/biz.exception'
import { CreatorPipe } from '~/common/pipes/creator.pipe'
import { UpdaterPipe } from '~/common/pipes/updater.pipe'
import { ErrorEnum } from '~/constants/error-code.constant'
import { Pagination } from '~/helper/paginate/pagination'
import { definePermission, Perm } from '~/modules/system/auth/decorators/permission.decorator'
import { RoleEntity } from '~/modules/system/role/role.entity'
import { SseService } from '~/modules/system/sse/sse.service'

import { MenuService } from '../menu/menu.service'

import { RoleQueryDto, RoleSaveDto } from './role.dto'
import { RoleInfo } from './role.model'
import { RoleService } from './role.service'

export const permissions = definePermission('system:role', {
  PAGE: 'page',
  QUERY: 'query',
  CREATE: 'create',
  UPDATE: 'update',
  DELETE: 'delete',
} as const)

@ApiTags('System - 角色模块')
@ApiSecurityAuth()
@Controller('role')
export class RoleController {
  constructor(
    private roleService: RoleService,
    private menuService: MenuService,
    @Inject(forwardRef(() => SseService))
    private sseService: SseService,
  ) {}

  @Get('page')
  @ApiOperation({ summary: '获取角色分页列表' })
  @ApiResult({ type: [RoleEntity], isPage: true })
  @Perm(permissions.PAGE)
  async page(@Query() dto: RoleQueryDto): Promise<Pagination<RoleEntity>> {
    return this.roleService.page(dto)
  }

  @Get('simple-list')
  @ApiOperation({ summary: '获取角色列表' })
  @ApiResult({ type: [RoleEntity] })
  async list(@Query() dto: RoleQueryDto): Promise<RoleEntity[]> {
    return this.roleService.list(dto)
  }

  @Get('get')
  @ApiOperation({ summary: '查询角色详情' })
  @ApiResult({ type: RoleInfo })
  @Perm(permissions.QUERY)
  async get(@Query('id') id: number): Promise<RoleInfo> {
    return this.roleService.info(id) as Promise<RoleInfo>
  }

  @Post('create')
  @ApiOperation({ summary: '创建角色' })
  @Perm(permissions.CREATE)
  async create(@Body(CreatorPipe) dto: RoleSaveDto): Promise<void> {
    await this.roleService.create(dto)
  }

  @Put('update')
  @ApiOperation({ summary: '更新角色' })
  @Perm(permissions.UPDATE)
  async update(@Body(UpdaterPipe) dto: RoleSaveDto): Promise<void> {
    if (!dto.id) {
      throw new BusinessException(ErrorEnum.REQUESTED_RESOURCE_NOT_FOUND)
    }

    await this.roleService.update(dto.id, dto)
    await this.menuService.refreshOnlineUserPerms(false)
    this.sseService.noticeClientToUpdateMenusByRoleIds([dto.id])
  }

  @Delete('delete')
  @ApiOperation({ summary: '删除单个角色' })
  @Perm(permissions.DELETE)
  async delete(@Query('id') id: number): Promise<void> {
    if (!id || Number.isNaN(id)) {
      throw new BusinessException(ErrorEnum.REQUESTED_RESOURCE_NOT_FOUND)
    }

    if (await this.roleService.checkUserByRoleId(id))
      throw new BadRequestException('该角色存在关联用户，无法删除')

    await this.roleService.delete(id)
    await this.menuService.refreshOnlineUserPerms(false)
    this.sseService.noticeClientToUpdateMenusByRoleIds([id])
  }

  @Delete('delete-list')
  @ApiOperation({ summary: '批量删除角色' })
  @Perm(permissions.DELETE)
  async deleteList(@Query() dto: DeleteDto): Promise<void> {
    // 解析ids参数
    const ids = dto.ids.split(',').map(id => Number.parseInt(id.trim())).filter(id => !Number.isNaN(id))

    if (ids.length === 0) {
      throw new BusinessException(ErrorEnum.REQUESTED_RESOURCE_NOT_FOUND)
    }

    // 批量删除
    for (const id of ids) {
      if (await this.roleService.checkUserByRoleId(id))
        throw new BadRequestException('该角色存在关联用户，无法删除')

      await this.roleService.delete(id)
      await this.menuService.refreshOnlineUserPerms(false)
      this.sseService.noticeClientToUpdateMenusByRoleIds([id])
    }
  }
}
